#if !defined(EA_2F0BB25C_958D_4575_9BFF_F212EEC23FF7__INCLUDED_)
#define EA_2F0BB25C_958D_4575_9BFF_F212EEC23FF7__INCLUDED_

#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <queue>
#include <limits>
#include <hash_set.h>

#include "Date.h"
#include "Inventory.h"
#include "Sale.h"
#include "Trade.h"
#include "Auction.h"
#include "SeeMenus.h"
#include "BST.h"

#define SAVE 0
#define LOAD 1

using namespace std;
using namespace __gnu_cxx;

struct ItemsHash {
	//hash function
	int operator()(const Item & tab) const {
		return tab.getID();
	}

	//equality function
	bool operator()(const Item & it1, const Item & it2) const {
		//compara items
		return (it1 == it2);
	}
};

typedef hash_set<Item, ItemsHash, ItemsHash> hashUnavailableItems;

class AntiqueStore {
public:
	AntiqueStore(string Store_filename, string Clients_filename,
			string Records_filename, string Catalogue_filename, string NonAvailItems_filename) :
		itemsCatalogue(Item()) {
		years_historic=2;
		welcome();
		loadAntiqueStore(Store_filename);
		loadClients(Clients_filename);
		loadRecords(Records_filename);
		loadCatalogue(Catalogue_filename);
		inventory.initializeRareItems();
		loadNonAvailItems(NonAvailItems_filename);
		inventory.initializeItemsQuantity();
	}

	virtual ~AntiqueStore() {
	}

	/* ======================================================
	 MENUS
	 ======================================================== */

	/** Visualizes welcome menu */
	void welcome();

	/** Main menu */
	void mainMenu();

	/** login menu */
	void menuLogin();

	/** Client registration menu */
	void menuRegister();

	/** Client login area menu */
	void menuLoginClient(Client* _client);

	/** Administrator login area menu */
	void menuLoginAdmin();

	/** Shows the information about all the clients registered in the antique store */
	void showClients(vector<Client*> _clients);

	/** menu to edit the information about a client */
	void menuEditClient(Client* _client);

	/** manage the preferences of the client */
	void menuPreferences(Client* _client);

	/** removes a registered client from the antique store */
	void removeClient(Client* _client);

	/** menu to add items to the antique store */
	void menuAddItems();

	/** menu to edit the information about a item */
	void menuEditItem_Options(Item* _item);

	/** menu for searching items */
	vector<Item*> menuSearchItems();

	/** Menu for searching transactions
	 * @return vector of pointers to transactions searched */
	vector<Transaction *> menuSearchTrans();

	/** @return vector of pointers to transactions searched with date d */
	vector<Transaction *> transSearchByDate(Date d);

	/** @return vector of pointers to transactions searched who have the client with ID client_id */
	vector<Transaction *> transSearchByClient(string client_id);

	/** @return vector of pointers to transactions searched who have the item with ID item_id */
	vector<Transaction *> transSearchByItem(unsigned int item_id);

	/** Menu for searching auctions
	 * @return vector of pointers to auctions searched */
	vector<Auction *> menuSearchAuctions();

	/** @return vector of pointers to auctions searched with starting date d */
	vector<Auction *> aucSearchByStartingDate(Date d);

	/** @return vector of pointers to auctions searched with end date d */
	vector<Auction *> aucSearchByEndDate(Date d);

	/** @return vector of pointers to auctions searched who have the client with ID client_id */
	vector<Auction *> aucSearchByClient(string client_id);

	/** @return vector of pointers to auctions searched who have the item with ID item_id */
	vector<Auction *> aucSearchByItem(unsigned int item_id);

	/** Menu for options of editing transaction _trans */
	void menuEditTrans_Options(Transaction* _trans);

	/** Menu for adding transactions */
	void menu_AddTransactions(string _owner);

	/* ======================================================
	 CLIENT FUNCTIONS
	 ========================================================= */

	/** Client menu for managing items of client _client */
	void menuClient_ManageItems(Client* _client);

	/** Client menu for managing rare items */
	void menuClient_RareItems(Client* _client);

	/** Client menu for editing items of client _client */
	void menuClient_EditItems(Client* _client);

	/** Client menu for managing transactions of client _client */
	void menuClient_ManageTransactions(Client* _client);

	/** @return vector of pointers to transactions searched by client */
	vector<Transaction *> menuClient_SearchTransactions();

	/** Client menu for removing transactions of client _client */
	void menuClient_RemoveTransactions(Client * _client);

	/** Client menu for managing auctions of client _client */
	void menuClient_ManageAuctions(Client* _client);

	/** @return vector of pointers to auctions searched by client */
	vector<Auction *> menuClient_SearchAuctions(); //because admin and client have different options to search.

	/** Client menu for managing bids of client _client */
	void menuClient_ManageBids(Client * _client);

	/** Client menu for placing bids of client _client */
	void menuClient_PlaceBids(Auction * _auction, Client * _client);

	/** Shows the information about the bids */
	void showBids(vector<Bid *> _bids);

	/** @return vector of pointers to bids searched by client */
	vector<Bid *> menuClient_SearchBids(Client * _client,
			vector<Auction *> clientAuc);

	/** Client menu for deleting profile */
	void menuClient_Profile(Client* _client);

	/** Client menu for deleting profile */
	void menuClient_Historic(Client *_client);

	/** Client menu for item historic options */
	void menuClient_HistoricMenu();

	/** Client menu for deleting profile */
	void menuClient_DeleteProfile(Client* _client);

	/** Client menu for buying items */
	void menuClient_BuyItem(Client* _client);

	/** Client menu for trading items */
	void menuClient_TradeItems(Client* _client);

	/* ======================================================
	 ADMINISTRATOR FUNCTIONS
	 ======================================================== */

	/** Admin menu for managing items */
	void menuAdmin_ManageItems();

	/** Admin menu for managing rare items */
	void menuAdmin_RareItems();

	/** Admin menu for editing items */
	void menuAdmin_EditItems();

	/** Admin menu for managing types */
	void menuAdmin_ManageTypes();

	/** Admin menu for removing items */
	void menuAdmin_RemoveItems();

	/** Admin menu for managing clients */
	void menuAdmin_ManageClients();

	/** Admin menu for editing clients */
	void menuAdmin_ManageClients_EditClients();

	/** Admin menu for showing clients found */
	void menuAdmin_ManageClients_ShowClientsFound();

	/** @return vector of pointers to the clients found by the search */
	vector<Client*> menuAdmin_SearchClients();

	/** @return vector of pointers to the clients found by the search by their ID */
	vector<Client*> menuAdmin_SearchClientsByID();

	/** @return vector of pointers to the clients found by the search by their name */
	vector<Client*> menuAdmin_SearchClientsByName();

	/** @return vector of pointers to the clients found by the search by their address */
	vector<Client*> menuAdmin_SearchClientsByAddress();

	/** @return vector of pointers to the clients found by the search by their phone number */
	vector<Client*> menuAdmin_SearchClientsByPhoneNumber();

	/** @return vector of pointers to the clients found by the search by their e-mail */
	vector<Client*> menuAdmin_SearchClientsByEmail();

	/** @return vector of pointers to the clients found by the search by their password */
	vector<Client*> menuAdmin_SearchClientsByPassword();

	/** Admin menu for removing clients */
	void menuAdmin_RemoveClients();

	/** Admin menu for removing client _client*/
	void menuAdmin_RemoveClient(Client* _client);

	/** Admin menu for managing transactions */
	void menuAdmin_ManageTransactions();

	/** Admin menu for removing transactions */
	void menuAdmin_RemoveTransactions();

	/** Removes transaction _transaction from transactions */
	void removeTransaction(Transaction * _transaction);

	/** Admin menu for current records */
	void menuAdmin_CurrentRecords();

	/** Admin menu for visualizing records */
	void menuAdmin_Historic();

	/** Admin menu for managing auctions */
	void menuAdmin_ManageAuctions();

	/** Admin menu for adding auctions */
	void menu_AddAuctions();

	/** Admin menu for removing auctions */
	void menuAdmin_RemoveAuctions();

	/** removes auction _auction from auctions */
	void removeAuction(Auction * _auction);

	/** @return a chosen client from the clients referenced in the vector<Client*> given */
	Client* chooseClient(vector<Client*> _clients);

	/** @return a chosen item from the items referenced in the vector<Item*> given */
	Item* chooseItem(vector<Item*> );

	/** Admin menu for buying items */
	void menuAdmin_BuyItem();

	/** Admin menu for trading items */
	void menuAdmin_TradeItems();

	/* ======================================================
	 RECORD
	 ======================================================== */

	/** @return the old_record of transactions*/
	vector<Transaction *> getTransRecord();

	/** @return the old_record of auction */
	vector<Auction *> getAucRecord();

	/** @return the new_record of transactions */
	vector<Transaction *> getCurrTrans();

	/** @return the new_record of auctions */
	vector<Auction *> getCurrAuc();

	/** @return the old_record of transactions of client _client */
	vector<Transaction *> getClientTransRecord(Client* _client);

	/** @return the old_record of auction of client _client */
	vector<Auction *> getClientAucRecord(Client* _client);

	/** @return the new_record of transactions of client _client */
	vector<Transaction *> getClientCurrTrans(Client* _client);

	/** @return the new_record of auctions of client _client */
	vector<Auction *> getClientCurrAuctions(Client* _client);

	/* ======================================================
	 AUXILIARY FUNCTIONS
	 ======================================================== */

	/** Shows the information about the transactions vector _trans */
	void showTransactions(vector<Transaction*> _trans);

	/** Shows the information about the auctions vector _aucs */
	void showAuctions(vector<Auction*> _aucs);

	/** @return transaction chosen from transactions vector v */
	Transaction* chooseTrans(vector<Transaction*> v);

	/** @return auction chosen from auctions vector v */
	Auction* chooseAuction(vector<Auction*> v);

	/** @return item chosen from auction with bids v */
	Item chooseAucItem(vector<Bid> v);

	/** @return the index of the type in the vector of types */
	unsigned int findType(Type _type);

	/**
	 * Manages the choice of the menu option so that, in case the user picks
	 * a number not available or writes a letter, the program won't accept the input
	 * and will ask again for a valid option.
	 *
	 * The string sentence is what appears before the user is given the choice.
	 */
	int manageOptionsWString(int n_options, string sentence);

	/** @return the client with the ID given */
	Client searchClientByID(string clientID);

	/** @return false if a client isn't in the antique store
	 * checks if a given client is already registered in the antique store */
	bool clientExists(Client _client);

	/** adds a client to the antique store */
	void addClient(Client c);

	/** Saves or Loads depending on option chosed */
	void saveAndLoad(string as_filename, string r_filename, string c_filename, string ca_filename, string na_filename, bool option);

	/* ======================================================
	 LOAD FUNCTIONS
	 ======================================================== */

	/** Loads AntiqueStore information from a .txt */
	void loadAntiqueStore(string filename);

	/** Loads Records information from a .txt */
	void loadRecords(string filename);

	/** Loads Clients information from a .txt */
	void loadClients(string filename);

	/** Loads Catalogue information from a .txt */
	void loadCatalogue(string filename);
	
	/** Loads non available items' information from a .txt */
	void loadNonAvailItems(string filename);

	/* ======================================================
	 SAVE FUNCTIONS
	 ======================================================== */

	/** Saves AntiqueStore information in a .txt */
	void saveAntiqueStore(string filename);

	/** Saves Records information in a .txt */
	void saveRecords(string filename);

	/** Saves Clients information in a .txt */
	void saveClients(string filename);
	
	/** Saves Catalogue information in a .txt */
	void saveCatalogue(string filename);
	
	/** Saves NonAvailItems information in a .txt */
	void saveNonAvailItems(string filename);

	/** Deletes all the information stored */
	void deleteDatabase();

	/** Updates owner of items' state when auction finishes */
	void updateInventory(string auctionID);
	
	/* ======================================================
	BST
	======================================================== */

	/** Admin menu for managing the itemsCatalogue */
	void menuManageBST_Admin();
	
	/** Client menu for managing the itemsCatalogue */
	void menuManageBST_Client(Client* _client);

	/** Menu for adding an item to the Catalogue */
	void menuAddToBST();
	
	/** Menu for editing an item in the Catalogue */
	void menuEditBST();
	
	/** Menu for searching items in the Catalogue
	 * @return items found in the Catalogue */
	vector<Item*> menuSearchBST();
	
	/** Menu for deleting an item from the Catalogue */
	void menuDeleteBST();
	
	/** Menu for selling an item to the Store that is in the Catalogue */
	void menuSaleBST(Client* _client);

	/** Adds an Item to itemsCatalogue. */
	void addItemToBST(const Item & item);
	
	/** Removes an Item from itemsCatalogue */
	void removeItemFromBST(const Item* item);
	
	/** shows the information about the Catalogue */
	void showBST();
	
	/** @param vector of pointers of items that are in the Catalogue
	 * @return pointer to chosen Item from the catalogue */
	Item* chooseItemBST(vector<Item*> _items);
	
	/** Copies the Catalogue's content into a vector of pointers
	 * @return vector of pointer of items that are in the Catalogue */
	vector<Item*> BSTToVector();
	
	/** items search by ID
	 * @return the items found in the search */
	vector<Item*> SearchBST_ItemID();
	
	/** items search by Name
	 * @return the items found in the search */
	vector<Item*> SearchBST_ItemName();

	/** items search by MainType
	 * @return the items found in the search */
	vector<Item*> SearchBST_ItemMaintype();
	
	/** items search by SubType
	 * @return the items found in the search */
	vector<Item*> SearchBST_ItemSubtype();
	
	/** items search by Age
	 * @return the items found in the search */
	vector<Item*> SearchBST_ItemAge();
	
	/** items search by Price
	 * @return the items found in the search */
	vector<Item*> SearchBST_ItemPrice();

	/* ======================================================
	 HASH_SET
	 ======================================================== */

	/** Admin menu for managing the NonAvailItems */
	void MenuAdmin_HistoricItems();

	/** Admin menu for adding items to the NonAvailItems table */
	void MenuAdmin_HistoricItems_Add();

	/** Admin menu for removing items from the NonAvailItems table */
	void MenuAdmin_HistoricItems_Remove();

	/** Admin menu for editing items in the NonAvailItems table */
	void MenuAdmin_HistoricItems_Edit();
	
	/** shows the information about the NonAvailItems */
	void listUnavailableItems();

	/** Updates the NonAvailItems table
	 * @param Item that will be added if it meets the conditions */
	void updateUnavailableItems(Item & _item);

	/** Removes an item from the NonAvailItems table
	 * "param Item that will be removed from the table */
	void removeFromUnavailableItems(Item & _item);

	/** Menu for searching items in the NonAvailItems table */
	vector<Item> menuSearchHash();

	/** items search by ID
	 * @return the items found in the search */
	vector<Item> searchHash_ID();

	/** items search by Name
	 * @return the items found in the search */
	vector<Item> searchHash_Name();

	/** items search by MainType
	 * @return the items found in the search */
	vector<Item> searchHash_Maintype();

	/** items search by SubType
	 * @return the items found in the search */
	vector<Item> searchHash_Subtype();

	/** items search by Age
	 * @return the items found in the search */
	vector<Item> searchHash_Age();

	/** items search by Price
	 * @return the items found in the search */
	vector<Item> searchHash_Price();
	
	/** Sets years_historic equal to _y */
	void setYearsHist(size_t _y){ this->years_historic = _y; }
	
	/** @return the number of years an item needs to enter the unavailableItems hash */
	size_t getYearsHist() const { return years_historic; }
private:
	string admin_pass;
	vector<Client> clients;
	Inventory inventory;
	vector<Transaction *> transactions;
	vector<Auction> auctions;

	Date sys_date;

	BST<Item> itemsCatalogue;

	size_t years_historic;//admin can edit this
	hashUnavailableItems historicUnavailableItems;
};
#endif // !defined(EA_2F0BB25C_958D_4575_9BFF_F212EEC23FF7__INCLUDED_)
